﻿using AutoMapper;
using Serilog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WCS_Entity.Dto.AutoEquipmentDto;
using WCS_Entity.Prorocol;
using WCS_Service.DomianService.Interface;
using WCS_Service.DomianService.Models;
using WCS_Service.Enums;
using WCS_Service.Interface;
using WCS_Service.ProtocolServices.Interface;
using WCS_Service.RcsServices;
using WCS_Utility.ConstString;

namespace WCS_Service.DomianService.AutoEquipmentDomain
{
    /// <summary>
    /// 自动化设备基础服务类
    /// </summary>
    public class AutoEquipmentDomainService<T> : IAutoEquipmentDomainService
    {
        protected ConcurrentDictionary<int, RunEqInfoModel<T>> controlEquipments { get; set; } = new();
        protected readonly IAutoEquipmentService _autoEquipmentService;
        private readonly IComControl _comControl;
        private readonly IMapper _mapper;
        #region 构造
        public AutoEquipmentDomainService(IAutoEquipmentService autoEquipmentService, IComControl comControl, IMapper mapper)
        {
            _autoEquipmentService = autoEquipmentService;
            _comControl = comControl;
            _mapper = mapper;
            _comControl.ConnectEquipmentChange += RunEquipmentUpdate;
        }
        #endregion
        /// <summary>
        /// 查询设备的点位
        /// </summary>
        /// <returns></returns>
        public async Task<string> QueryEqSiteAsync(int eqNumber)
        {
            return await Task.Run(() => 
            {
                if (!controlEquipments.ContainsKey(eqNumber))
                {
                    return null;
                }
                if (!controlEquipments.TryGetValue(eqNumber, out RunEqInfoModel<T> info))
                {
                    return null;
                }
                return info.mapSite;
            });
        }

        public async Task AddConEquipmentAsync(int key, AutoEquipmentDto model, Func<string, Task<Func<string,int, Task>?>> execute =null)
        {
            var runEqInfoModel = _mapper.Map<RunEqInfoModel<T>>(model);
            if(runEqInfoModel is null) return;
            //构建各个自动化设备独有的设备信息
            runEqInfoModel.customInfo = await CustomEqInfoInitProcess(model);
            var info = controlEquipments.AddOrUpdate(key, runEqInfoModel, (key, value) => value);
            if (info is not null)
            {
                var manage = await _comControl.QueryServiceBaseId(key);
                if (manage is null) return;
                var protocolService = manage.protocolService;
                if (protocolService is null) return;
                await ProtocolServiceInitAsync(protocolService, manage.protocolPara, execute);
            }
        }

        public async Task RemoveConEquipmentAsync(int key)
        {
            if (!controlEquipments.ContainsKey(key))
            {
                return;
            }
            var flag = controlEquipments.TryGetValue(key, out var equipment);
            if (!flag)
            {
                return;
            }
            KeyValuePair<int, RunEqInfoModel<T>> removeValue =
               new KeyValuePair<int, RunEqInfoModel<T>>(key, equipment);
            controlEquipments.TryRemove(removeValue);
        }

        protected virtual async void RunEquipmentUpdate(int id, ConEquipmentState state,string type)
        {
            if (state == ConEquipmentState.Connect && !controlEquipments.ContainsKey(id))
            {
                //查询指定的自动化设备
                var autoEqInfo = await _autoEquipmentService.QueryAutoEquipmentAsync(id);
                if (autoEqInfo is null) return;
                var equipmentInfo = _mapper.Map<RunEqInfoModel<T>>(autoEqInfo);
                controlEquipments.AddOrUpdate(id, equipmentInfo, (key, value) => value);
            }
            else if (state == ConEquipmentState.DisConnect && controlEquipments.ContainsKey(id))
            {
                var flag = controlEquipments.TryGetValue(id, out var equipment);
                if (!flag || equipment is null)
                {
                    return;
                }
                KeyValuePair<int, RunEqInfoModel<T>> removeValue =
                   new KeyValuePair<int, RunEqInfoModel<T>>(id, equipment);
                controlEquipments.TryRemove(removeValue);
            }
        }

        protected virtual async Task<T> CustomEqInfoInitProcess(AutoEquipmentDto dto)
        {
            return default(T);
        }

        protected virtual async Task ProtocolServiceInitAsync(IProtocolService service,List<ProtocolEntity> protocolParas, Func<string, Task<Func<string,int, Task>?>> execute)
        {
            return;
        }
        protected async Task<bool> ComServiceProcessAsync(int id,Func<IComBaseDomainManage,Task> execute)
        {
            var manage = await _comControl.QueryServiceBaseId(id);
            if (manage is null)
            {
                Log.Error($"设备{id}通信服务获取失败");
                return false;
            }
            await execute(manage);
            return true;
        }
        /// <summary>
        /// 根据设备ID查询对应的通信服务
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        protected async Task<IComBaseDomainManage?> QueryComServiceBaseId(int id)
        {
            var manage = await _comControl.QueryServiceBaseId(id);
            if (manage is null)
            {
                Log.Error($"设备{id}通信服务获取失败");
                return null;
            }
            return manage;
        }
        /// <summary>
        /// 更新自动化设备可使用标志位
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        protected async Task UpdateEquipmentAvailableAsync(int key,bool state)
        {
            await Task.Run(() => 
            {
                var flag = controlEquipments.TryGetValue(key, out var equipment);
                if (!flag || equipment is null)
                {
                    return;
                }
                equipment.available = state;
                controlEquipments.AddOrUpdate(key,equipment, (key, value) => value);
            });
        }

        #region private
        #endregion
    }
}
